<?php
/*
*All rights reserved: Json.
*Links:http://www.liyaoquan.cn.
*Links:http://imarkchina.cn.
*Links:http://www.imarkchina.cn.
*/
Class DbMysqli extends Db {
	Private Static $_instance = null;

	Public Static function getInstance() {
		if (is_null(self::$_instance)) self::$_instance = new self();
		return self::$_instance;
	}

	Private Static $_connect = array();

	Private function _connect() {
		$connectId = md5(serialize($this->config));

		if (isset(self::$_connect[$connectId])) return self::$_connect[$connectId];

		if ($this->config['DB_LONG_CONNECT'] == true) {
			if (substr(PHP_VERSION, 0, 3) < 5.3) throw new Exception(__METHOD__.' [PHP5.3以上才支持Mysqli长连接, 需将DB_LONG_CONNECT配置为false]');
		}

		$host = $this->config['DB_LONG_CONNECT'] == true ? 'p:'.$this->config['DB_HOST'] : $this->config['DB_HOST'];
		self::$_connect[$connectId] = new Mysqli($host,
		$this->config['DB_USER'],
		$this->config['DB_PASSWORD'],
		$this->config['DB_NAME'],
		$this->config['DB_PORT']);
		if (self::$_connect[$connectId]->connect_errno) {
			throw new Exception(__METHOD__.' [数据库连接失败: '.iconv('GBK', 'UTF-8', self::$_connect[$connectId]->connect_error).']');
		}
		self::$_connect[$connectId]->set_charset($this->config['DB_CHARSET']);
		return self::$_connect[$connectId];
	}

	Public function escapeString($string) {
		$Mysqli = $this->_connect();
		return $Mysqli->real_escape_string($string);
	}

	Public function query($sql, $method = '') {
		$startTime = microtime(true);
		$method = strtolower($method);
		$sql = $this->parse('prefix', $sql);
		$Mysqli = $this->_connect();
		if ($method == 'fetch' || $method == 'fetchall' || $method == 'query' || $method == 'count')
		$isSelect = true;
		if (isset($isSelect)) {
			$result = $stmt = $Mysqli->query($sql);
		} else {
			$stmt = $Mysqli->prepare($sql);
			if (!empty($stmt)) $result = $stmt->execute();
		}
		if (!$method) return $result;
		if (!$stmt) throw new Exception('SQL错误: '.$sql.'<br />错误提示: '.$Mysqli->error);
		$result = array();
		switch ($method) {
			case 'fetch':
			$result = $stmt->fetch_assoc();
			break;
			case 'fetchall':
			if (method_exists('mysqli_result', 'fetch_all')) { //Compatibility layer with PHP < 5.3
				$result = $stmt->fetch_all(1);
			} else {
				for ($result = array(); $tmp = $stmt->fetch_array(1);) $result[] = $tmp;
			}
			break;
			case 'count':
			$row = $stmt->fetch_assoc();
			$result = !empty($row) ? reset($row) : 0;
			break;
			case 'insert':
			$result = $Mysqli->insert_id;
			break;
			case 'update':
			case 'delete':
			$result = $stmt->affected_rows;
			break;
		}
		self::$countQuery++;
		$stopTime = microtime(true);
		J::debug('[用时<font color="red">'.round(($stopTime - $startTime), 4).'</font>秒]: '.$sql);
		return $result === null ? array() : $result;
	}

	Public function getFields() {
		if (!$this->table) return;
		$dbname = '';
		if (!empty($this->config['DB_NAME']) && !stristr($this->table, $this->config['DB_NAME'])) {
			$dbname = $this->config['DB_NAME'].'.';
		}
		$cacheFile = SQL.$dbname.$this->table.'.php';
		if (is_file($cacheFile)) {
			return unserialize(str_replace('<?php exit();//', '', file_get_contents($cacheFile)));
		}
		$startTime = microtime(true);
		$Mysqli = $this->_connect();
		$sql = 'DESC '.$this->table;
		$query = $Mysqli->query($sql);
		if (!$query) {
			throw new Exception(__METHOD__.' [获取表'.$this->table.'字段失败: '.$Mysqli->error.']');
		}
		$fields = array();
		while ($row = $query->fetch_assoc()) {
			if ($row['Key'] == 'PRI') {
				$fields['pk'] = strtolower($row['Field']);
			} else {
				$fields[] = strtolower($row['Field']);
			}
		}
		//如果不存在主键，则提取第一个字段为主键
		if (!array_key_exists('pk', $fields)) $fields['pk'] = array_shift($fields);
		self::$countQuery++;
		if (!empty($fields['pk'])) {
			$stopTime = microtime(true);
			J::debug('[用时<font color="red">'.round(($stopTime - $startTime), 4).'</font>秒]: '.$sql, 2);
			J::makeDir(dirname($cacheFile));
			file_put_contents($cacheFile, '<?php exit();//'.serialize($fields));
			return $fields;
		}
	}

	Public function beginTransaction() {
		$Mysqli = $this->_connect();
		$Mysqli->autocommit(false);
	}

	Public function commit() {
		$Mysqli = $this->_connect();
		$Mysqli->commit();
		$Mysqli->autocommit(true);
	}

	Public function rollBack() {
		$Mysqli = $this->_connect();
		$Mysqli->rollback();
		$Mysqli->autocommit(true);
	}

	Public function lastInsertId() {
		$Mysqli = $this->_connect();
		return $Mysqli->insert_id;
	}

	Public function getVersion() {
		$Mysqli = $this->_connect();
		return $Mysqli->server_info;
	}
}